package com.smx.xname;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.Vector;
import java.util.TimerTask;
import java.net.URL;

import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfig;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.XmlRpcConfig;


public class Updater {

    // The host address for SECVPN
    public static final String RPC_HOST_ADDRESS = "http://www.xname.org/xmlrpc.php";


    String name;
    String newIP;
    String zone;
    String TTL;
    private String basedir=System.getProperty("xname.basedir");
    private String lastIP;
    private PropertiesContainer container;
    private IPFinder IPDetect;
    private Timer xp=new Timer();

    public Updater(){
        container=new PropertiesContainer();
        IPDetect=new IPFinder();
    }
    /**
     * @param args
     */

    public static void main(String[] args) {
        // Create the client, identifying the server
        Updater app=new Updater();
        app.initSystem();

        /*
           app.setName("tester");
           app.setNewIP("127.0.0.5");
           app.setZone("justchugit.com");
           app.doUpdate();
           */
    }
    private void initSystem(){

        try{
            if(basedir==null){
               System.out.println("xname.basedir property not set using application path directory");
               basedir=com.smx.xname.util.Directory.getApplicationPath()+"\\";
            }
            System.out.println("basedir="+basedir);
             
            BufferedReader bf=new BufferedReader(
                    new InputStreamReader(new FileInputStream(basedir+ "zones.txt")));

            String inputLine=null;
            String lastContainer="";
            while((inputLine=bf.readLine())!=null){

                // Skip #comment char or blank lines
                if(!inputLine.startsWith("#") && !inputLine.equals("")){
                    if(inputLine.startsWith("$")){
                        lastContainer=inputLine;
                    }else{
                        addLineToContainer(lastContainer, inputLine);
                    }
                }

            }
            bf.close();

            BufferedReader brLast=new BufferedReader(new InputStreamReader(new FileInputStream(basedir+ "last.txt")));
            lastIP=brLast.readLine();

            if(lastIP==null || lastIP.trim().equals("")){
                lastIP="12.0.0.1";
            }
            brLast.close();
            int refreshRate=Integer.parseInt(container.readProperty("$settings","refreshrate"));
            xp.schedule(new UpdateSchedule(),100, refreshRate);

            System.out.println("refreshRate="+refreshRate);
            System.out.println("basedir="+basedir);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
    /**
     * This function parses out settigns and zones from config file and puts them in PropertiesContainer
     * @param _setting
     * @param _inputLine
     * @see PropertiesContainer
     */
    private void addLineToContainer(String _setting,String _inputLine){
        //System.out.println("Adding:"+_setting+"="+_inputLine);

        if(_setting.equals("$settings")){
            String sTemp[]=_inputLine.split("=");
            container.setProperty("$settings",sTemp[0], sTemp[1]);
            //		System.out.println(sTemp[0]+"=="+container.readProperty("$settings",sTemp[0]));
        }

        if(_setting.equals("$zones")){
            String sTemp[]=_inputLine.split("\\|");
            String collectedData="";
            String delim="|";
            for(int i=1;i<sTemp.length;++i){
                if(i==sTemp.length-1)delim="";

                collectedData+=sTemp[i]+delim;
            }
            container.setProperty("$zones",sTemp[0], collectedData);
            //	System.out.println(container.readProperty("$zones",sTemp[0]));
        }

        //container.setProperty("DBLogin","username","greg");
        //System.out.println(container.readProperty("DBLogin","username"));
    }


    public String doUpdate(){
        String ans="";
        try{
            System.out.println("Sending request");
            XmlRpcClient client =    new XmlRpcClient();
            XmlRpcClientConfigImpl config=  new XmlRpcClientConfigImpl();
            config.setServerURL(new URL( RPC_HOST_ADDRESS ));

            // Create a hashtable and add a circle request
            Hashtable<String,String> requestHash = new Hashtable<String,String>(  );
            requestHash.put("user", container.readProperty("$settings","username"));
            requestHash.put("password",container.readProperty("$settings","password"));
            requestHash.put("zone", getZone());
            requestHash.put("ttl", getTTL());
            requestHash.put("name", getName());
            requestHash.put("oldaddress", "*");
            requestHash.put("newaddress",getNewIP());
            // Create the request parameters using user input
            Vector params = new Vector(  );
            params.addElement(requestHash);

            System.out.println(requestHash);
            // Issue a request
            // Object result =  client.execute("xname.updateArecord", params);
            Object result =  client.execute(config, "xname.updateArecord", params);

            // Report the results
            System.out.println("Result="+ result.toString(  ));
            ans= result.toString(  );

            try{
                boolean append = true;
                PrintWriter out=new PrintWriter(
                        new BufferedWriter(new FileWriter(basedir+"update.log",append)));
                out.write(ans+"\n");
                out.close();

            }catch(Exception ex){
                ex.printStackTrace();
            }


        }catch (Exception e) {
            e.printStackTrace();
            ans=e.getMessage();}
        return ans;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNewIP() {
        return newIP;
    }
    public void setNewIP(String newIP) {
        this.newIP = newIP;
    }
    public String getZone() {
        return zone;
    }
    public void setZone(String zone) {
        this.zone = zone;
    }
    /**
     *
     * @author Administrator
     * Inner class that executes periodical updates to the system
     */
    class UpdateSchedule extends TimerTask
    {
        /**
         * Steps:
         * <ul>
         * <li>Detect IP</li>
         * <li>Compare to lastIP</li>
         *  <li>Update/Skip</li>
         *   <li>Update last.txt file with new IP</li>
         * </ul>
         */
        @Override
        public void run() {
            String detectedIP="";
            try {
                detectedIP=IPDetect.detectIP();
            } catch (NotEnoughSourcesException e) {
                //provide loopback interface     
                detectedIP="127.0.0.1";
            }
            //68.93.181.139
            //detectedIP="68.93.181.139";
            if(lastIP.equals(detectedIP)){
                System.out.println("No update necessary");
                return;
            }
            lastIP=detectedIP;

            try{
                PrintWriter out=new PrintWriter( new BufferedWriter(new FileWriter(basedir+ "last.txt")));

                out.write(detectedIP);
                out.close();

            }catch(Exception ex){
                ex.printStackTrace();
            }

            //Get All the Zones and update them one by one
            Map<String,Map> zones=container.getPropertyMap("$zones");
            System.out.println("zones="+zones);
            Iterator<Map.Entry<String,Map>> it=zones.entrySet().iterator();
            while(it.hasNext()){

                Map.Entry entry=it.next();
                String zoneName=entry.getKey().toString();

                String zoneValues=entry.getValue().toString();
                String vals[]=zoneValues.split("\\|");

                //for each www entry do an update
                for(int k=1;k<vals.length;++k){
                    setZone(zoneName);
                    setNewIP(detectedIP);
                    setTTL(vals[0]);
                    setName(vals[k]);
                    doUpdate();
                }

                System.out.println("Updated:"+zoneName);
            }

        }

    }
    public String getTTL() {
        return TTL;
    }
    public void setTTL(String ttl) {
        TTL = ttl;
    }
}
